import CommonUtils from "./CommonUtils";
import ResUtils from "./ResUtils";
import App from "./framework/App";

const KEY_MUSIC_VOLUME = 'Key_BGMVolume';
const KEY_EFFECT_VOLUME = 'Key_VoiceVolume';

const MUSIC_VOLUME = 0.2;
const EFFECT_VOLUME = 1;

/** 对前一个仍在播放的声音的重播规则 */
export enum AudioOverrideMethod {
    /** 停止所有当前正在播放的用类声音（同是Music或同是Effect） */
    StopAll,
    /** 当前同名的声音在播放则停掉 */
    SameNameStop,
    /** 当前同名的声音在播放则返回 */
    SameNameReturn,
    /** 如果当前声音未播放完则返回 */
    AlwaysReturn
}

export default class AudioManager {

    static isVoicePlaying = false;

    private static clips: { [key: string]: cc.AudioClip } = {};
    private static currMusicName: string;
    private static currVoices: { [key: string]: number } = {};
    private static currVoicesQueue: string[] = [];
    private static currFXs: { [key: string]: number } = {};
    private static currFXsQueue: string[] = [];

    //持久化音量配置,UI滑块直接赋值即可
    static set musicVolumeProgress(progress: number) { cc.audioEngine.setMusicVolume(MUSIC_VOLUME * progress); localStorage.setItem(KEY_MUSIC_VOLUME, progress + ''); }
    static get musicVolumeProgress() { let progress = localStorage.getItem(KEY_MUSIC_VOLUME); if (progress) return Number(progress); return MUSIC_VOLUME; }
    static set effectsVolumeProgress(progress: number) { cc.audioEngine.setEffectsVolume(EFFECT_VOLUME * progress); localStorage.setItem(KEY_EFFECT_VOLUME, progress + ''); }
    static get effectsVolumeProgress() { let progress = localStorage.getItem(KEY_EFFECT_VOLUME); if (progress) return Number(progress); return EFFECT_VOLUME; }

    /** 播放目录resources/audios/目录下的背景音乐,默认覆盖当前正在的播放的音乐
     * @param overrideMethod 默认AudioOverrideMethod.StopAll
     * @param usePreload 默认true
     */
    static playBGM(fileName: string, overrideMethod: AudioOverrideMethod = AudioOverrideMethod.StopAll, usePreload: boolean = true, onLoadedAndPlay?: Function) {
        if (cc.audioEngine.getMusicVolume() != AudioManager.musicVolumeProgress) {
            cc.audioEngine.setMusicVolume(AudioManager.musicVolumeProgress);
        }

        //如果已经播放，处理覆盖规则
        if (cc.audioEngine.isMusicPlaying) {
            switch (overrideMethod) {
                case AudioOverrideMethod.StopAll:
                    break;
                case AudioOverrideMethod.SameNameStop:
                    if (AudioManager.currMusicName != fileName) {
                        return;
                    }
                    break;
                case AudioOverrideMethod.SameNameReturn:
                    if (AudioManager.currMusicName == fileName) {
                        return;
                    }
                    break;
                case AudioOverrideMethod.AlwaysReturn:
                    return;
            }
        }
        AudioManager.currMusicName = fileName;

        let clip = AudioManager.clips[fileName];
        if (clip) {
            cc.audioEngine.playMusic(clip, true);
            if (onLoadedAndPlay) {
                onLoadedAndPlay();
            }
        } else {
            let audioUrl: string = AudioManager.getUrl(fileName);
            if (usePreload) {
                let clip = App.instance.resPreloader.getRes(audioUrl);
                cc.audioEngine.playMusic(clip, true);
                AudioManager.clips[fileName] = clip;
                if (onLoadedAndPlay) {
                    onLoadedAndPlay();
                }
            } else {
                ResUtils.loadAudio(audioUrl, (clip) => {
                    cc.audioEngine.playMusic(clip, true);
                    AudioManager.clips[fileName] = clip;
                    if (onLoadedAndPlay) {
                        onLoadedAndPlay();
                    }
                })
            }
        }
    }
    static pauseBGM() {
        cc.audioEngine.pauseMusic();
    }
    static stopBGM() {
        cc.audioEngine.stopMusic();
    }
    static resumeBGM() {
        //cc.audioEngine.resumeMusic();//无效
        let clip = AudioManager.clips[AudioManager.currMusicName];
        cc.audioEngine.playMusic(clip, true);
    }

    /** 随机播放目录resources/audios/目录下的人声，默认停掉之前的所有人声 */
    static playRandomVoices(fileNames: string[], overrideMethod: AudioOverrideMethod = AudioOverrideMethod.StopAll) {
        AudioManager.playVoice(fileNames[CommonUtils.randomInt(0, fileNames.length)], overrideMethod);
    }

    /** 按顺序播放数组里的人声（目录resources/audios），默认停掉之前的所有人声 */
    static playQueueVoices(fileNames: string[], overrideMethod: AudioOverrideMethod = AudioOverrideMethod.StopAll) {
        AudioManager.currVoicesQueue = [];
        for (let i = 0; i < fileNames.length; i++) {
            AudioManager.currVoicesQueue.push(fileNames[i]);
        }
        AudioManager.playQueueVoice(overrideMethod);
    }
    private static playQueueVoice(overrideMethod: AudioOverrideMethod) {
        if (AudioManager.currVoicesQueue.length > 0) {
            let fileName = AudioManager.currVoicesQueue[0];
            AudioManager.currVoicesQueue.splice(0, 1);
            AudioManager.playVoice(fileName, overrideMethod, true, () => { AudioManager.playQueueVoice(overrideMethod); });
        }
    }

    /** 播放目录resources/audios/目录下的人声，默认停掉之前的所有人声 */
    static playVoice(fileName: string, overrideMethod: AudioOverrideMethod = AudioOverrideMethod.StopAll, usePreload: boolean = true, onPlayEnd?: Function) {
        console.log('播放人声：' + fileName);
        if (cc.audioEngine.getEffectsVolume() != AudioManager.effectsVolumeProgress) {
            cc.audioEngine.setEffectsVolume(AudioManager.effectsVolumeProgress);
        }
        //如果已经播放，处理覆盖规则
        if (AudioManager.isVoicePlaying) {
            switch (overrideMethod) {
                case AudioOverrideMethod.StopAll:
                    for (const key in AudioManager.currVoices) {
                        let audioId = AudioManager.currVoices[key];
                        if (audioId >= 0) {
                            cc.audioEngine.stopEffect(audioId);
                        }
                    }
                    AudioManager.currVoices = {};
                    break;
                case AudioOverrideMethod.SameNameStop:
                    let audioId = AudioManager.currVoices[fileName];
                    if (audioId >= 0) {
                        cc.audioEngine.stopEffect(audioId);
                        AudioManager.currVoices[fileName] = -1;
                    }
                    break;
                case AudioOverrideMethod.SameNameReturn:
                    audioId = AudioManager.currVoices[fileName];
                    if (audioId >= 0) {
                        return;
                    }
                    break;
                case AudioOverrideMethod.AlwaysReturn:
                    return;
            }
        }

        let clip = AudioManager.clips[fileName];
        if (clip) {
            AudioManager.doPlayVoice(clip, fileName, onPlayEnd);
        } else {
            let audioUrl: string = AudioManager.getUrl(fileName);
            if (usePreload) {
                let clip = App.instance.resPreloader.getRes(audioUrl);
                if (!clip) {
                    console.error('加载失败: ' + audioUrl);
                }
                AudioManager.doPlayVoice(clip, fileName, onPlayEnd);
                AudioManager.clips[fileName] = clip;
            } else {
                ResUtils.loadAudio(audioUrl, (clip) => {
                    if (!clip) {
                        console.error('加载失败: ' + audioUrl);
                    }
                    AudioManager.doPlayVoice(clip, fileName, onPlayEnd);
                    AudioManager.clips[fileName] = clip;
                });
            }
        }
    }
    private static doPlayVoice(clip: cc.AudioClip, fileName: string, onPlayEnd: Function) {
        AudioManager.isVoicePlaying = true;
        let audioId = cc.audioEngine.playEffect(clip, false);
        AudioManager.currVoices[fileName] = audioId;
        cc.audioEngine.setFinishCallback(audioId, () => {
            AudioManager.currVoices[fileName] = -1;
            AudioManager.isVoicePlaying = false;
            if (onPlayEnd) {
                onPlayEnd();
            }
        });
    }
    /** 停止特定人声 */
    static stopVoice(fileName: string) {
        let audioId = AudioManager.currVoices[fileName];
        if (audioId >= 0) {
            cc.audioEngine.stopEffect(audioId);
            AudioManager.currVoices[fileName] = -1;
        }
    }

    /** 按顺序播放数组里的人声（目录resources/audios），默认停掉之前的所有人声 */
    static playQueueFXs(fileNames: string[], usePreload = true) {
        AudioManager.currFXsQueue = [];
        for (let i = 0; i < fileNames.length; i++) {
            AudioManager.currFXsQueue.push(fileNames[i]);
        }
        AudioManager.playQueueFX(usePreload);
    }
    private static playQueueFX(usePreload) {
        if (AudioManager.currFXsQueue.length > 0) {
            let fileName = AudioManager.currFXsQueue[0];
            AudioManager.currFXsQueue.splice(0, 1);
            AudioManager.playFX(fileName, usePreload);
        }
    }

    /** 播放目录resources/audios/目录下的音效，保留之前的音效 */
    static playFX(fileName: string, usePreload = true) {
        if (cc.audioEngine.getEffectsVolume() != AudioManager.effectsVolumeProgress) {
            cc.audioEngine.setEffectsVolume(AudioManager.effectsVolumeProgress);
        }
        let clip = AudioManager.clips[fileName];
        if (clip) {
            AudioManager.doPlayFX(clip, fileName);
        } else {
            let audioUrl: string = AudioManager.getUrl(fileName);
            if (usePreload) {
                let clip = App.instance.resPreloader.getRes(audioUrl);
                AudioManager.doPlayFX(clip, fileName);
                AudioManager.clips[fileName] = clip;
            } else {
                ResUtils.loadAudio(audioUrl, (clip) => {
                    AudioManager.doPlayFX(clip, fileName);
                    AudioManager.clips[fileName] = clip;
                })
            }
        }
    }
    private static doPlayFX(clip: cc.AudioClip, fileName: string) {
        let audioId = cc.audioEngine.playEffect(clip, false);
        AudioManager.currFXs[fileName] = audioId;
        cc.audioEngine.setFinishCallback(audioId, () => {
            AudioManager.currFXs[fileName] = -1;
        });
    }
    /** 停止特定音效 */
    static stopFX(fileName: string) {
        let audioId = AudioManager.currFXs[fileName];
        if (audioId >= 0) {
            cc.audioEngine.stopEffect(audioId);
            AudioManager.currFXs[fileName] = -1;
        }
    }
    /** 除背景音乐外，其他声音全部停止 */
    static stopAllVoicesAndFXs() {
        cc.audioEngine.stopAllEffects();
    }

    /** 停止全部背景音乐和人声和音效 */
    static stopAllSounds() {
        cc.audioEngine.stopAll();
    }

    private static getUrl(fileName): string {
        return 'audios/' + fileName;
    }

}
